package jdk8.functions;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class DemoStreamReduce {

    public static void main(String[] args) {
        testReduce();

        // testParallelReduce();
    }

    public static void testReduce(){
        List<Integer> numbers = Stream.iterate(1, x -> x + 1).limit(10).collect(Collectors.toList());
        Integer aa = 0;
        for(Integer i : numbers){
            aa += i;
        }

        // reduce第三个参数只在parallelStream中才生效
        Integer dd = numbers.stream().reduce(0, (a,b) -> a + b, (a, b) -> a - b);
        System.out.println(dd);

        dd = numbers.stream().reduce(10, (a,b) -> a + b, (a, b) -> a - b);
        System.out.println(dd);

        dd = numbers.parallelStream().reduce(10, (a,b) -> a + b, (a, b) -> a + b);
        System.out.println(dd);

        dd = numbers.parallelStream().reduce(1000, (a,b) -> a + b, (a, b) -> a - b);
        System.out.println(dd);

        Optional<Integer> dd1 = numbers.stream().reduce((a, b) -> a + b);
        System.out.println(aa);
        System.out.println(dd1.get());
    }

    public static void testParallelReduce(){
        //accumulator不写入list,不需要线程同步,初始值使用普通的list
        List<Integer> list = new ArrayList<>();
        AtomicInteger accumulateCount = new AtomicInteger(0);
        AtomicInteger combineCount = new AtomicInteger(0);
        List<Integer> reduceResult = IntStream.range(0, 100)
                .parallel()
                .boxed()
                .reduce(list, (i, j) -> {
                    System.out.println(String.format("* thread name:%s, i === %s, j === %s", Thread.currentThread().getName() , i, j));
                    accumulateCount.incrementAndGet();
                    //不改变初始的i,而是返回一个新的i
                    ArrayList<Integer> newI = new ArrayList<>(i);
                    newI.add(j);
                    return newI;
                }, (i, j) -> {
                    System.out.println(String.format("****i==j: %s, thread name:%s, i === %s, j === %s", i == j, Thread.currentThread().getName() , i, j));
                    combineCount.incrementAndGet();
                    ArrayList<Integer> newI = new ArrayList<>(i);
                    newI.addAll(j);
                    return newI;
                });
        System.out.println("---------------------------------------");
        System.out.println("reduce result : "+reduceResult);
        System.out.println("reduce result size: "+reduceResult.size());
        System.out.println("accumulateCount: "+accumulateCount.get());
        System.out.println("combineCount: "+combineCount.get());
        System.out.println("list: "+ list);

    }


}
